/**
 * 
 */
package fhq.hcmute.edu.vn.system.util;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Stack;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.IOFileFilter;
import org.apache.commons.io.filefilter.TrueFileFilter;

import fhq.hcmute.edu.vn.system.FileType;
import fhq.hcmute.edu.vn.system.MyFile;
import fhq.hcmute.edu.vn.system.MyFolder;
import fhq.hcmute.edu.vn.system.MySystem;

/**
 * @author nglehien Oct 30, 2012 - 10:20:28 PM
 */
public class DiskManager {
	public static boolean IS_ROOT = true;
	public static String INVALID = "INVALID";
	public static String ROOT = "ROOT";
	public static Stack<MyFolder> stack;

	private static void initStack() {
		if (stack.isEmpty()) {
			MyFolder myFolder = getItemsContain(ROOT);
			stack.push(myFolder);
		}
	}

	static {
		stack = new Stack<>();
		initStack();
	}

	/**
	 * return current folder.
	 * 
	 * @return
	 */
	public static MyFolder list() {
		if (!stack.isEmpty()) {
			MyFolder currentFolder = stack.peek();
			print(currentFolder);
			return currentFolder;
		}
		return null;
	}

	/**
	 * change directory to.
	 * 
	 * @param directoryName
	 * @return
	 */
	public static boolean changeDirectory(String directoryName) {
		if (!stack.isEmpty()) {
			String path = INVALID;
			if (!(path = getPath(directoryName)).equals(INVALID)) {
				MyFolder folder = getItemsContain(path);
				stack.push(folder);
				return true;
			}
		}
		return false;
	}

	private static MyFolder getItemsContain(String path) {
		File[] files = null;
		boolean isRoot = false;
		if (path.equals(ROOT)) {
			files = File.listRoots();
			isRoot = true;
		} else {
			files = (new File(path)).listFiles();
			isRoot = false;
		}
		MyFolder myFolder = new MyFolder();
		for (int i = 0; i < files.length; i++) {
			File file = files[i];
			if (isRoot) {
				if (file.isDirectory()) {
					String pathTemp = (file.getParent() == null) ? file
							.getPath() : file.getParent();
					MyFolder temp = new MyFolder(pathTemp, ROOT,
							file.isHidden(), isRoot);
					temp.setFileType(FileType.harddisk);
					temp.setPath(temp.getPath().replace("\\", ""));
					myFolder.add(temp);
				}
			} else {
				if (files[i].isDirectory()) {
					MyFolder temp = new MyFolder(file.getName(),
							(file.getParent() == null) ? file.getPath()
									: file.getParent(), file.isHidden(), isRoot);
					if (isRoot) {
						temp.setPath(temp.getPath().replace("\\", ""));
					}
					myFolder.add(temp);
				} else if (file.isFile()) {
					MyFile temp = new MyFile(file.getName(),
							(file.getParent() == null) ? file.getPath()
									: file.getParent(), file.isHidden());
					if (isRoot) {
						temp.setPath(temp.getPath().replace("\\", ""));
					}
					myFolder.add(temp);
				}
			}
		}
		myFolder.setPath(path);
		return myFolder;
	}

	private static String getPath(String name) {
		ArrayList<MySystem> itemsInFolder = stack.peek().getFolders();
		for (MySystem item : itemsInFolder) {
			if (item instanceof MyFolder) {
				if (((MyFolder) item).isRoot()) {
					String temp = item.getName();
					if (temp.toLowerCase().equals(name.toLowerCase())) {
						return name;
					}
				} else {
					if (item.getName().toLowerCase().equals(name.toLowerCase())) {
						return (item.getPath() + "\\" + name);
					}
				}
			}
		}
		return INVALID;
	}

	public static MyFolder refresh() {
		MyFolder currentFolder = pwd();
		String path = "";
		if (currentFolder.isRoot()) {
			path = ROOT;
		} else {
			path = currentFolder.getPath() + "\\" + currentFolder.getName();
		}
		return getItemsContain(path);
	}

	/**
	 * go back one level.
	 * 
	 * @return
	 */
	public static boolean changeDirectory() {
		if (!stack.isEmpty()) {
			stack.pop();
			return true;
		}
		return false;
	}

	/**
	 * return current working directory
	 * 
	 * @return
	 */
	public static MyFolder pwd() {
		if (!stack.isEmpty()) {
			return stack.peek();
		}
		return null;
	}

	public static void upToRoot() {
		stack = new Stack<>();
		initStack();
	}

	public static void print(MySystem folder) {
		for (int i = 0; i < ((MyFolder) folder).getFolders().size(); i++) {
			MySystem system = ((MyFolder) folder).getFolders().get(i);
			System.out.println(system.getPath() + "\\" + system.getName());
		}
	}

	public static final MyFolder search(MyFolder path, final String name,
			final String[] conds) {
		if (path == null) {
			path = pwd();
			path.setName("");
		}
		MyFolder folder = new MyFolder();
		File f = null;
		if (path.isRoot()) {
			f = new File(path.getName());
		} else {
			f = new File(path.getPath() + "\\"
					+ (path.getName() == null ? "" : path.getName()));
		}

		IOFileFilter filefil = new IOFileFilter() {

			private boolean checkFileType(String fileName, String[] conds) {
				for (int i = 0; i < conds.length; i++) {
					if (fileName.endsWith(conds[i]))
						return true;
				}
				return false;
			}

			private boolean check(File fi, String name, String[] conds) {
				boolean isOK = false;
				String lowercaseName = fi.getName().toLowerCase();
				if (conds == null && name != null) {// Search Name
					name = name.toLowerCase();
					isOK = lowercaseName.startsWith(name);
				} else if (name == null && conds != null) { // Search Type
					isOK = checkFileType(lowercaseName, conds);
				} else if (name == null && conds == null) { // NULL
					return true;
				} else { // Search Name + Type
					name = name.toLowerCase();
					isOK = (lowercaseName.startsWith(name) & checkFileType(
							lowercaseName, conds));
				}
				return isOK;
			}

			@Override
			public boolean accept(File arg0, String fileName) {
				return false;
			}

			@Override
			public boolean accept(File arg0) {
				if (check(arg0, name, conds)) {
					System.out.println(arg0.getName());
					return true;
				} else {
					return false;
				}
			}
		};

		Collection<File> files = FileUtils.listFiles(f, filefil,
				TrueFileFilter.INSTANCE);

		for (File file : files) {
			if (file.isFile()) {
				MyFile myFile = new MyFile(file.getName(), file.getParent(),
						file.isHidden());
				folder.add(myFile);
			}
		}
		return folder;
	}
}
